/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PYTHON_OBJ_HH
#define PYTHON_OBJ_HH

/* base class used as example */
class reference_class
{
    int reserved, dtor_error;

    // this is the reference counter
    int refcnt;

public:
    reference_class();
    virtual ~reference_class();

    inline void incref() {refcnt++;}
    reference_class *decref();
    int get_refcnt();
    void show_dtor_refcnt_error();
    void declare_local_or_member();

    virtual int virtual_method(int x);
};

// TYPEDEF / STRUCT
typedef struct _sample_struct_
{
    int member_int;
    double member_double;
} sample_struct;

// REFERENCE COUNTED CLASS
class sample_class : public reference_class
{
    unsigned short payload;

public:
    sample_class();
    sample_class(int x, int y);
    ~sample_class();

    // to test generalization
    virtual int virtual_method(int x);
};

class specialized_class : public sample_class
{
    double x;
    bool extrange[9876];

public:
    specialized_class();
    ~specialized_class();

    // to test generalization
    virtual int virtual_method(int x);
};

// OBJ_CONTAINER CLASS
class container_class
{
    sample_struct sample_str_obj;
    sample_class sample_obj;
    sample_struct *sample_str_objp;
    sample_class *sample_objp;

    // to test generalization
    reference_class *refobj;

public:
    container_class();
    ~container_class();

    // obtain reference counts
    int get_sample_objp_refcnt();

    // pass a pointer to object
    void pass_objp(sample_class *objp);
    void pass_objp(sample_struct *objp);

    // return pointers to objects
    sample_class *get_sample_class();
    sample_struct *get_sample_struct1();
    sample_struct *get_sample_struct2();

    // create a new contained objects
    void new_sample_objp();
    void new_sample_str_objp();

    // return by reference
    sample_struct &refret_struct1();
    sample_struct &refret_struct2();
};

// classes to test P3 hierarchy
class sample_embed4
{
public:
    sample_struct emb;
    int reserved;

    sample_embed4();
};

class sample_embed3
{
public:
    sample_embed4 emb;
    sample_struct emb_;
    int reserved;
};

class sample_embed2
{
public:
    sample_embed3 emb;
    sample_embed4 emb_;
    int reserved;
};

class sample_embed1
{
public:
    sample_embed2 emb;
    sample_embed3 emb_;
    int reserved;
};

// reference counts in detail
class reference_counter
{
    int refcnt;

    // ** PRIVATE METHODS **

protected:
    reference_counter();
    virtual ~reference_counter();

public:
    inline void incref() {refcnt++;}
    reference_counter *decref();
};

class counted1: public reference_counter
{
    int c1_member;
    char *c1_cad;

public:
    counted1();
    ~counted1();
    void init(char *cad);
};

class counted2: public reference_counter
{
    int c2_member;

public:
    counted2();
    ~counted2();
    counted1 *new_counted1();
};

// object array
class array_container
{
    int pad;
    bool bpad;

    struct to_create_array
    {
	int x, y;
	float f;
	double d;
	bool b[12];
	struct inner_obj_array
	{
	    bool b;
	    int value;
	} inner_array_object[13];
    } array_object[7];

public:
    array_container();

    int get_value(int x, int y);
    void set_value(int x, int y, int value);
};

// vector of objects and object pointers (non ref-counted)
class object_vector
{
    struct obj
    {
	int x;
	double y;
	bool z;
	float v[12];
    };

    // vector of object pointers
    obj **w;
    int n_w, max_w;

    // vector of objects
    obj *v;
    int n_v, max_v;

public:
    object_vector();
    ~object_vector();

    void add_v();
    void add_w();
};

// multiple embedded P4
class p4_1
{
    int x;
public:
    p4_1();
    ~p4_1();
};

class p4_2
{
    p4_1 *p;
public:
    p4_2();
    ~p4_2();
};

class p4_3
{
    p4_2 *p;
public:
    p4_3();
    ~p4_3();

    void del_p();
};


#endif
